<?php

class Page extends BasePage
{
    // FQL fields, used for RT updates
    public static $rt_info_fields = array(
        'name', 'picture');

    private $page_info = null;


    /**
     * Returns true if the install process was completed.
     */
    public function isInstalled()
    {
        return !$this->Profile->isNew();
    }


    public function isSmartPage()
    {
        return $this->Profile->is_smart_sort_activated || $this->Profile->is_smart_share_activated;
    }


    public function updateInfo()
    {
        // Call the Facebook API only once
        if ($this->page_info !== null)
            return;
        if (!$this->page_id)
            return;
        $this->page_info = false;

        try {
            $page_info = App::call_api($this->page_id, array('metadata' => 1));
            vtnsLog::debug('Page Graph info: '.var_export($page_info, true));

            if (!is_array($page_info))
                throw new Exception("API error");

            $this->page_info = $page_info;
            $this->doUpdateInfo($this->page_info);
        } catch (Exception $e) {
            vtnsLog::error("{Page} updateInfo: ".$e->getMessage());
            // Do update PageProfile.link
            $this->doUpdateInfo(array());
        }
    }


    public function doUpdateInfo($info)
    {
        if (!empty($info['name']))
            $this->Profile->name = $info['name'];

        if (!empty($info['picture']))
            $this->Profile->picture = $info['picture'];

        if (!empty($info['logo_url']))
            $this->Profile->picture = $info['logo_url'];

        if (!empty($info['link']))
            $this->Profile->link = $info['link'];
        elseif (!$this->Profile->link)
            // A page MUST have a link
            $this->Profile->link = 'http://www.facebook.com/pages/p/'.$this->page_id;

        if (isset($info['type'])) {
            $this->Profile->type = $info['type'];
            if ($info['type'] === 'page') {
                if (empty($info['has_added_app'])) {
                    if ($this->State->has_added_app) {
                        $this->State->has_added_app = false;
                        $this->State->uninstalled_at = date(DATE_ISO8601);
                    }
                } else {
                    $this->State->has_added_app = true;
                }
            }
        }
        if (isset($info['likes'])) {
            $this->PageStats->likes_count = $info['likes'];
            $this->Stats->likes = $info['likes'];
        }

        if (isset($info['category']))
            $this->Profile->category = $info['category'];

        if (!empty($info)) {
            $this->Profile->is_places = isset($info['location']['latitude']) && isset($info['location']['longitude']);

            $this->Profile->rt_valid = true;
            $this->Profile->rt_updated_at = date(DATE_ISO8601);
        }

        if (!$this->Profile->isNew())
            $this->save();
    }


    public function getName()
    {
        if (!$this->Profile->name)
            $this->updateInfo();
        return $this->Profile->name;
    }


    /**
     * Ne renvoie pas une chaîne vide car est utilisée directement dans une URL : aaa//bbb casse le routing.
     */
    public function getNameSlug()
    {
        $slug = Doctrine_Inflector::urlize($this->Profile->name);
        return $slug ? $slug : 'page';
    }


    public function getPicture()
    {
        if (!$this->Profile->picture)
            $this->updateInfo();
        return $this->Profile->picture;
    }


    public function hasAddedApp()
    {
        if ($this->page_info === null)
            $this->updateInfo();
        return $this->page_info && $this->page_info['has_added_app'];
    }

    public function getBillingEmail()
    {
        if (!empty($this->Profile->billing_email))
            return $this->Profile->billing_email;
        foreach($this->Admins as $admin) {
            if (!empty($admin->User->email)){
                vtnsLog::infoToMongo('no_billing_email', 'email for page_id #'.$this->page_id.' taken from page_admin and sent at <'.$admin->User->email.'>');
                return $admin->User->email;
            }
        }
    }


    /**
     * Returns the URL for the app tab on the page profile.
     *
     * For standard pages :
     *   http://www.facebook.com/pages/<page name>/<page id>?v=app_<app id>
     *
     * For application pages :
     *   http://www.facebook.com/apps/application.php?id=<page id>&sk=app_<app id>
     */
    private function getTabUrl($api_id)
    {
        if (!$this->Profile->link)
            $this->updateInfo();

        $url = $this->Profile->link;

        if (sfConfig::get('sf_facebook_enable_beta_tier'))
            $url = strtr($url, array('www.facebook' => 'www.beta.facebook'));

        if (strpos($url, '?') !== false)
            $url .= '&';
        else
            $url .= '?';

        $type = ($this->Profile->type == 'application') ? 'sk=app_' : 'v=app_';
        return $url.$type.$api_id;
    }


    public function getCurrentTabUrl($embedded = null)
    {
        $current_api_id = $this->Profile->current_api_id;
        return $this->getTabUrl($current_api_id);
    }


    public function getPreviousTabUrl()
    {
        if ($this->Profile->previous_api_id)
            return $this->getTabUrl($this->Profile->previous_api_id);
        else
            return $this->getCurrentTabUrl();
    }


    /**
     * Returns the URL that will point to redirect_list action.
     * We can pass an array of GET parameters to it.
     */
    public function getPermaLink(array $get_parameters = array())
    {
        $params = array(
                'company' => $this->getNameSlug(),
                'page_id' => $this->page_id,
            );
        $get_parameters = http_build_query(array_merge($get_parameters,$params));
        return UrlFunctions::genUrl('@redirect_list?'.$get_parameters, true);
    }


    public function getJobsQuery()
    {
        $q = Doctrine_Query::create()
            ->from('Job j')
            ->where('j.page_id = ?', $this->page_id);
        return $q;
    }


    public function getReferralJobsQuery($filters=null)
    {
        $q = $this->getActiveJobsQuery();

        if ($filters) {
            $jobs_filters = fssUtil::doubleExplode('=', '&', $filters);

            if (!empty($jobs_filters['cat']))
                $q->leftJoin('j.Categories cat')
                    ->WhereIn('cat.cat_id',$jobs_filters['cat']);

            if (!empty($jobs_filters['contract']))
                $q->leftJoin('j.Values vcon WITH vcon.field_id = 10')
                    ->WhereIn('vcon.data_key',$jobs_filters['contract']);

            if (!empty($jobs_filters['country']))
                $q->leftJoin('j.Values vcou WITH vcou.field_id = 9')
                    ->WhereIn('vcou.data_key',$jobs_filters['country']);

            if (!empty($jobs_filters['location']))
                $q->leftJoin('j.Values vloc WITH vloc.field_id = 8')
                    ->addWhere('LOWER(vloc.value) REGEXP ?',strtolower(implode('|', $jobs_filters['location'])));
        }

        return $q;
    }


    public function getActiveJobsQuery()
    {
        $q = $this->getJobsQuery();
        return (sfConfig::get('sf_app') == 'fsmartshop') ?
            Doctrine_Core::getTable('Job')->addActiveRegardlessOfModerationJobsQuery($q) :
            Doctrine_Core::getTable('Job')->addActiveJobsQuery($q);
    }

    public function getActiveRegardlessOfModerationJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addActiveJobsQuery($q);
    }


    public function getActiveJobsCount()
    {
        return $this->getActiveJobsQuery()->count();
    }

    public function getActiveRegardlessOfModerationJobsCount()
    {
        return $this->getActiveRegardlessOfModerationJobsQuery()->count();
    }

    public function getShowCandidateJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addShowCandidateJobsQuery($q);
    }


    public function getShowCandidateJobsCount()
    {
        return $this->getShowCandidateJobsQuery()->count();
    }


    public function getCurrentJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addCurrentJobsQuery($q);
    }


    public function getInactiveJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addInactiveJobsQuery($q);
    }

    public function getInactiveRegardlessOfModerationJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addInactiveRegardlessOfModerationJobsQuery($q);
    }

    public function getInactiveRegardlessOfModerationJobsCount()
    {
        return $this->getInactiveRegardlessOfModerationJobsQuery()->count();
    }

    public function getInactiveJobsCount()
    {
        return $this->getInactiveJobsQuery()->count();
    }

    public function getPendingModerationJobsQuery()
    {
        $q = $this->getJobsQuery();
        return Doctrine_Core::getTable('Job')->addPendingModerationJobsQuery($q);
    }


    public function getPendingModerationJobsCount()
    {
        return $this->getPendingModerationJobsQuery()->count();
    }


    /**
     * Change the number of allowed jobs on the frontoffice.
     * Use 0 for an unlimited number of slots.
     *
     * If more than the allowed number of jobs are active, the oldest
     * jobs are marked as paused.
     *
     * Returns:
     *   - 1 if free slots are available
     *   - 0 if no slot is available but no job was paused
     *   - -1 if no slot is available and some jobs were paused
     */
    public function setJobSlots($job_slots)
    {
        $this->Profile->job_slots = $job_slots;
        $this->save();

        if (!$job_slots)
            return 1;

        $q = $this->getActiveJobsQuery();
        $job_count = $q->count();

        if ($job_count < $job_slots) {
            return 1;
        } elseif ($job_count == $job_slots) {
            return 0;
        } else {
            $this->pauseOldestJobs($job_count - $job_slots);
            return -1;
        }
    }


    /**
     * Pause a number of the oldest jobs.
     */
    public function pauseOldestJobs($job_count, $import_only = false)
    {
        sfContext::getInstance()->getLogger()->info("{Page} Trying to pause up to $job_count jobs");

        $q = $this->getActiveJobsQuery()
            ->addOrderBy('j.refreshed_at ASC')
            ->addOrderBy('j.job_id ASC')
            ->limit($job_count);

        if ($import_only)
            $q->innerJoin('j.Values AS jv_import WITH jv_import.field_id = ?', Field::getIdForName('import'))
                ->addWhere('jv_import.value IS NOT NULL')
                ->addWhere('jv_import.value <> ?', '\'\'');

        $paused_count = 0;
        foreach ($q->execute() as $job) {
            $job->pause();
            ++$paused_count;
        }
        return $paused_count;
    }


    public function hasJobSlots()
    {
        if (sfConfig::get('sf_app') == 'fsmartshop')
            return true;

        if (!$this->Profile->job_slots)
            return true;

        return ($this->getActiveJobsCount() < $this->Profile->job_slots);
    }


    public function addCredits($amount)
    {
        if ($amount <= 0)
            throw new Exception("Invalid credit amount '$amount'");

        $this->Profile->credit_amount += $amount;
        $this->Profile->save();
    }


    public function substractCredits($amount)
    {
        if ($amount <= 0)
            throw new Exception("Invalid credit amount '$amount'");

        if ($this->Profile->credit_amount < $amount)
            return false;

        $this->Profile->credit_amount -= $amount;
        $this->Profile->save();
        return true;
    }


    public function getJobPostedDuringInstall()
    {
        $job = $this->getCurrentJobsQuery()->fetchOne();
        if (!$job || $job->getValue('import')) // Job imported via Indeed or the API
            return null;
        else
            return $job;
    }


    public function getAPICredentials()
    {
        $api_credentials = $this->_get('ApiCredentials');
        if ($api_credentials->isNew()) {
            sfContext::getInstance()->getLogger()->err("{Page} Creating API credentials for page: ".$this->page_id);
            $api_credentials->updateFromPlan($this->PagePlan->Plan);
            if (!$this->isNew())
                $api_credentials->save();
        }
        return $api_credentials;
    }

    /// getNetwork will
    /// return a SchoolFacebookNetwork if this school has a network
    /// return null otherwise
    public function getNetwork()
    {
        //hey, on sql too much here, we could find this by FK,
        //do this by sorting out how Doctrine create $this->Network when no SchoolFacebookNetwork matches
        $network = Doctrine_Query::create()
                ->from('SchoolFacebookNetwork sfn')
                ->where('sfn.page_id = ?', $this->page_id)
                ->fetchOne();
        if(!$network)
        {
            return null;
        }
        return $network;
    }

    public function save(Doctrine_Connection $conn = null)
    {
        if($this->getPageId()){
            parent::save($conn);
        }
    }

    public static function create($user, $page_id)
    {
        sfContext::getInstance()->getLogger()->info("Creating page with page_id:".$page_id);
        $page = new Page();
        $page->page_id = $page_id;
        $page->save();
        return $page;
    }


    public function isJobBoard()
    {
        return (sfConfig::get('sf_feature_job_board') && !$this->JobBoard->isNew());
    }

    /// {{{

    public function getMongoPage()
    {
        return MongoPage::findOrCreateOneByPageId((int)$this->page_id);
    }

    // }}}

	public function sendAddingCreditsAlertMail($credits_added, $type='auto', $new_value=null)
    {
        $new_credit_amount = $type == 'auto' ? $this->Profile->credit_amount + $credits_added : $new_value;
        $subject = 'Page profile changed in Admin space';
        $body  = "Hello,<br/><br/>";
        $body .= "The Page Profile credits ads has been changed for this page:<br/> Page Name = {$this->Profile->name} <br/> PageID = {$this->page_id}<br/> Link of Page: {$this->Profile->link} <br/> Credits information:<br/> Old credits: {$this->Profile->credit_amount} <br/> New credits: {$new_credit_amount}";
        $mail_to = sfConfig::get('sf_payment_mail_to');
        sfContext::getInstance()->getMailer()->composeAndSendPartial(
            array(sfConfig::get('sf_payment_mail_from') => sfConfig::get('sf_payment_name_from')),
            $mail_to,
            $subject,
            'generic',
            array('content' => $body)
        );
    }


    public function createStats()
    {
        // create a record of Stats if page was installed by super admin interface
        $this->Stats;
    }
}

